package com.netflexitysolutions.amazonws.sdb.orm.filter;

import java.util.StringTokenizer;

/**
 * Utility for parsing and building SimpleDB SQL queries.
 * 
 * @author netflexity
 *
 */
public final class SimpleDBSelectQueryUtil {

    /**
     * @return the token right after the first occurrence of "from"
     * in the query.
     */
	public static String from(String query) {
        String lastTok = "";
        boolean inQuote = false;
        StringTokenizer st = new StringTokenizer(query, " \t\r\n'\\", true);
        while (st.hasMoreTokens()) {
            String tok = st.nextToken();
            if (tok.equalsIgnoreCase("from") && !inQuote) {
                while (st.hasMoreTokens()) {
                    String tok2 = st.nextToken();
                    if (tok2.trim().length() >0)
                        return tok2;
                }
                break;
            }
            lastTok = tok;
            if (tok.equals("'") && !lastTok.equals("\\"))
                inQuote = !inQuote;
        }
        return null;
    }

    /**
     * @return the string that comes after the first occurrence of "where"
     */
	public static String where(String query) {
        if (query == null)
            return null;
        int index = 0;
        boolean inQuote = false;
        String lastTok = "";
        StringTokenizer st = new StringTokenizer(query, " \t\r\n'\\", true);
        while (st.hasMoreTokens()) {
            String tok = st.nextToken();
            index += tok.length();
            if (tok.equalsIgnoreCase("where") && !inQuote)
                break;
            lastTok = tok;
            if (tok.equals("'") && !lastTok.equals("\\"))
                inQuote = !inQuote;
        }
        return query.substring(index);
    }

    /**
     * This is equivalent to calling matchLikeString(s, like, '\\')
     */
	public static boolean matchLikeString(String s, String like) {
        return matchLikeString(s, like, '\\');
    }

    /**
     * A routine that does the Ansi SQL 'LIKE' comparison.
     * @param s the string to compare
     * @param like the expression to match against
     * @param escape the escape character to put a literal '%' or '_'
     *               in the expression
     * @return true if this is a match.
     */
	public static boolean matchLikeString(String s, String like, char escape) {
        if (like.length() == 0) {
            return s.length() == 0;
        }
        if (like.charAt(0) == '%') {
            int i;
            for (i = 1; (i < like.length() && like.charAt(i) == '%'); i++);
            if (like.length() <= i) {
                return true;
            }
            like = like.substring(i);
            for (i = 0; i < s.length(); i++) {
                if (matchLikeStringNoPercent(s, i, like, escape)) {
                    return true;
                }
            }
            return false;
        }
        return matchLikeStringNoPercent(s, 0, like, escape);
    }

	/**
	 * @param s
	 * @param j
	 * @param like
	 * @param escape
	 * @return
	 */
	private static boolean matchLikeStringNoPercent(
        String s, int j, String like, char escape)
    {
        int i = 0;
        int length = like.length();
        int slength = s.length() - j;
        while (i < like.length()) {
            char c = like.charAt(i);
            if (c == '%') {
                return matchLikeString(s.substring(j),
                                       like.substring(i),
                                       escape);
            }
            if (j >= s.length()) {
                break;
            }
            if (c == escape) {
                i++;
                if (i >= like.length()) {
                    return false;
                }
                length--;
                c = like.charAt(i);
                if (c != s.charAt(j)) {
                    return false;
                }
            }
            if (c != '_' && c != s.charAt(j)) {
                return false;
            }
            i++;
            j++;
        }
        return length == slength;
    }
}
